﻿Imports System.ComponentModel

Namespace Controls

    Friend Class ctlMergeChangeset

        Private Sub ctlMergeChangeset_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Try
                Dim oServers As List(Of TFSServer) = TfsApi.GetRegisteredServers()

                For Each oServer As TFSServer In oServers
                    cboServers.Items.Add(oServer)
                Next

                ' Sort the list
                cboServers.Sorted = True
                ' Now remove the sorting
                cboServers.Sorted = False
                ' Add in the empty item
                cboServers.Items.Insert(0, String.Empty)

                Show()
            Catch oExp As Exception
                If (Not Visible) Then Show()
                Helper.DisplayException(oExp, Me, "Exception Getting Team Projects")
            End Try
        End Sub

        Private Sub SetStatus(ByVal message As String)
            lblStatus.Text = message.Trim()
            Application.DoEvents()
        End Sub

        Private Function GetCollection() As TFSCollection
            Return DirectCast(cboCollections.SelectedItem, TFSCollection)
        End Function

        Private Sub cboServers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboServers.SelectedIndexChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading server information...")
                cboCollections.Items.Clear()
                cboCollections.Enabled = False
                cboProjects.Items.Clear()
                cboProjects.Enabled = False
                cboBranchDestination.Items.Clear()
                cboBranchDestination.Enabled = False
                cboBranchSource.Items.Clear()
                cboBranchSource.Enabled = False
                ClearChangesetDetailsAndGrid()
                ClearMergeCandidatesGrid()

                If (String.IsNullOrWhiteSpace(cboServers.SelectedItem.ToString())) Then Return

                Dim oServer As TFSServer = DirectCast(cboServers.SelectedItem, TFSServer)

                Dim clcCollections As List(Of TFSCollection) = TfsApi.GetTeamProjectCollections(oServer)

                For Each oCollection As TFSCollection In clcCollections
                    cboCollections.Items.Add(oCollection)
                Next

                cboCollections.Enabled = (cboCollections.Items.Count > 0)

                ' Insert after setting enabled
                cboCollections.Items.Insert(0, String.Empty)

                ' Default if only one collection is found
                If (cboCollections.Items.Count = 2) Then cboCollections.SelectedIndex = 1
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Collections")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub cboCollections_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboCollections.SelectedIndexChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading team projects...")
                cboProjects.Items.Clear()
                cboProjects.Enabled = False
                cboBranchDestination.Items.Clear()
                cboBranchDestination.Enabled = False
                cboBranchSource.Items.Clear()
                cboBranchSource.Enabled = False
                ClearChangesetDetailsAndGrid()
                ClearMergeCandidatesGrid()

                If (cboCollections.SelectedItem IsNot Nothing) AndAlso (String.IsNullOrWhiteSpace(cboCollections.SelectedItem.ToString())) Then Return

                Dim oCollection As TFSCollection = GetCollection()

                Dim clcProjects As List(Of TFSProject) = TfsApi.GetTeamProjects(oCollection, False)

                For Each oProject As TFSProject In clcProjects
                    cboProjects.Items.Add(oProject)
                Next

                cboProjects.Enabled = (cboProjects.Items.Count > 0)

                If (cboProjects.Enabled) Then
                    ' Default to the first if we only have one
                    If (cboProjects.SelectedIndex < 0) AndAlso (cboProjects.Items.Count = 1) Then cboProjects.SelectedIndex = 0
                End If
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Team Projects")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub cboProjects_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboProjects.SelectedIndexChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading source branches...")
                cboBranchSource.Items.Clear()
                cboBranchDestination.Items.Clear()
                cboBranchSource.Enabled = False
                cboBranchDestination.Enabled = False
                ClearChangesetDetailsAndGrid()
                ClearMergeCandidatesGrid()

                If (cboProjects.SelectedItem IsNot Nothing) AndAlso (String.IsNullOrWhiteSpace(cboProjects.SelectedItem.ToString())) Then Return

                Dim oProject As TFSProject = DirectCast(cboProjects.SelectedItem, TFSProject)

                Dim clcSourceBranches As List(Of TFSBranch) = TfsApi.GetBranches(GetCollection(), oProject)

                For Each oBranch As TFSBranch In clcSourceBranches
                    cboBranchSource.Items.Add(oBranch)
                Next

                cboBranchSource.Enabled = (cboBranchSource.Items.Count > 0)

                ' If we don't already have an item, default to the first one
                If cboBranchSource.Enabled AndAlso (cboBranchSource.SelectedIndex < 0) Then cboBranchSource.SelectedIndex = 0
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Source Branches")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub cboBranchSource_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboBranchSource.SelectedIndexChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading destination branches...")
                ClearMergeCandidatesGrid()
                ClearChangesetDetailsAndGrid()
                cboBranchDestination.Items.Clear()
                cboBranchDestination.Enabled = False

                If (cboBranchSource.SelectedItem IsNot Nothing) AndAlso (String.IsNullOrWhiteSpace(cboBranchSource.SelectedItem.ToString())) Then Return

                Dim oSourceBranch As TFSBranch = DirectCast(cboBranchSource.SelectedItem, TFSBranch)

                Dim clcDestinationBranches As List(Of TFSBranch) = TfsApi.GetRelatedBranches(GetCollection(), oSourceBranch)

                For Each oBranch As TFSBranch In clcDestinationBranches
                    cboBranchDestination.Items.Add(oBranch)
                Next

                cboBranchDestination.Enabled = (cboBranchDestination.Items.Count > 0)

                ' If we don't already have an item, default to the first one
                If cboBranchDestination.Enabled AndAlso (cboBranchDestination.SelectedIndex < 0) Then cboBranchDestination.SelectedIndex = 0
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Destination Branches")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub GetMergeCandidates()
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading merge candidates...")

                ClearMergeCandidatesGrid()
                ClearChangesetDetailsAndGrid()

                Dim oDtCandidates As DataTable = New DataTable("Merges")
                oDtCandidates.Columns.Add(Constants.MergeChangeset.BranchDataTableColumns.SELECTED, GetType(Boolean))
                oDtCandidates.Columns.Add(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_ID, GetType(Integer))
                oDtCandidates.Columns.Add(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_DATE, GetType(DateTime))
                oDtCandidates.Columns.Add(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_USER, GetType(String))
                oDtCandidates.Columns.Add(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_COMMENT, GetType(String))
                oDtCandidates.Columns.Add(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_LINK, GetType(String))

                Dim oSourceBranch As TFSBranch = DirectCast(cboBranchSource.SelectedItem, TFSBranch)
                Dim oDestinationBranch As TFSBranch = DirectCast(cboBranchDestination.SelectedItem, TFSBranch)

                For Each oCandidate As TFSMergeCandidate In TfsApi.GetMergeCandidates(GetCollection(), oSourceBranch, oDestinationBranch)
                    Dim oDrChangeset As DataRow = oDtCandidates.NewRow()
                    oDrChangeset(Constants.MergeChangeset.BranchDataTableColumns.SELECTED) = False
                    oDrChangeset(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_ID) = oCandidate.ChangesetId
                    oDrChangeset(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_DATE) = oCandidate.ChangesetDate
                    oDrChangeset(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_USER) = oCandidate.User
                    oDrChangeset(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_COMMENT) = oCandidate.Comment
                    oDrChangeset(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_LINK) = oCandidate.Link
                    oDtCandidates.Rows.Add(oDrChangeset)
                Next

                oDtCandidates.AcceptChanges()
                lblCandidatesFound.Text = String.Format("Total Changesets Found: {0}", oDtCandidates.Rows.Count)

                grdMergeCandidates.AutoGenerateColumns = False

                m_oBindingSourceMergeCandidates.DataSource = oDtCandidates
                grdMergeCandidates.DataSource = m_oBindingSourceMergeCandidates

                grdMergeCandidates.AutoResizeColumns()

            Catch oExp As Exception
                Cursor.Current = oCursor
                grdMergeCandidates.DataSource = Nothing
                Helper.DisplayException(oExp, Me, "Exception Getting Merge Candidates")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub ClearMergeCandidatesGrid()
            If (m_oBindingSourceMergeCandidates.DataSource IsNot Nothing) Then
                Dim oDtPrevious As DataTable = DirectCast(m_oBindingSourceMergeCandidates.DataSource, DataTable)
                oDtPrevious.Dispose()
                m_oBindingSourceMergeCandidates.DataSource = Nothing
                lblCandidatesFound.Text = "Total Changesets Found:"
            End If
            m_oBindingSourceMergeCandidates.Filter = String.Empty
            txtCandidateFilter.Text = String.Empty
        End Sub

        Private Sub grdMergeCandidates_SelectionChanged(sender As Object, e As EventArgs) Handles grdMergeCandidates.SelectionChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading changeset details...")

                If (m_oBindingSourceMergeCandidates.Current Is Nothing) Then
                    ClearChangesetDetailsAndGrid()
                    Return
                End If

                Dim oDrCurrent As DataRow = DirectCast(m_oBindingSourceMergeCandidates.Current, DataRowView).Row

                Dim iChangesetId As Integer = oDrCurrent(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_ID)

                Dim oChangesetDetails As TFSChangesetDetails = TfsApi.GetChangesetDetails(GetCollection(), iChangesetId)

                ClearChangesetDetailsAndGrid()

                ' Now bind the changeset details
                Dim oDtChanges As DataTable = New DataTable("Changes")
                oDtChanges.Columns.Add(Constants.MergeChangeset.ChangesetChangeDataTableColumns.CHANGE_NAME, GetType(String))
                oDtChanges.Columns.Add(Constants.MergeChangeset.ChangesetChangeDataTableColumns.CHANGE_TYPES, GetType(String))
                oDtChanges.Columns.Add(Constants.MergeChangeset.ChangesetChangeDataTableColumns.ITEM_IN_FOLDER, GetType(String))

                For Each oTfsChange As TFSChange In oChangesetDetails.Changes
                    Dim oDrChange As DataRow = oDtChanges.NewRow()
                    oDrChange(Constants.MergeChangeset.ChangesetChangeDataTableColumns.CHANGE_NAME) = oTfsChange.Name
                    oDrChange(Constants.MergeChangeset.ChangesetChangeDataTableColumns.CHANGE_TYPES) = oTfsChange.ChangeTypes
                    oDrChange(Constants.MergeChangeset.ChangesetChangeDataTableColumns.ITEM_IN_FOLDER) = oTfsChange.ContainingFolder
                    oDtChanges.Rows.Add(oDrChange)
                Next

                oDtChanges.AcceptChanges()

                grdChangesetDetails.AutoGenerateColumns = False
                m_oBindingSourceChangesetDetails.DataSource = oDtChanges
                grdChangesetDetails.DataSource = m_oBindingSourceChangesetDetails
                grdChangesetDetails.AutoResizeColumns()

                ' Now bind the work item details, if any
                Dim oDtWorkItems As DataTable = New DataTable("WorkItems")
                oDtWorkItems.Columns.Add(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_ID, GetType(Integer))
                oDtWorkItems.Columns.Add(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_STATE, GetType(String))
                oDtWorkItems.Columns.Add(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_TITLE, GetType(String))
                oDtWorkItems.Columns.Add(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_TYPE, GetType(String))
                oDtWorkItems.Columns.Add(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_LINK, GetType(String))

                For Each oWorkItem As TFSWorkItem In oChangesetDetails.WorkItems
                    Dim oDrWorkItem As DataRow = oDtWorkItems.NewRow()
                    oDrWorkItem(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_ID) = oWorkItem.Id
                    oDrWorkItem(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_STATE) = oWorkItem.State
                    oDrWorkItem(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_TITLE) = oWorkItem.Title
                    oDrWorkItem(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_TYPE) = oWorkItem.Type
                    oDrWorkItem(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_LINK) = oWorkItem.Link
                    oDtWorkItems.Rows.Add(oDrWorkItem)
                Next

                oDtWorkItems.AcceptChanges()

                grdWorkItems.AutoGenerateColumns = False
                m_oBindingSourceWorkItems.DataSource = oDtWorkItems
                grdWorkItems.DataSource = m_oBindingSourceWorkItems
                grdWorkItems.AutoResizeColumns()

            Catch oExp As Exception
                Cursor.Current = oCursor
                grdMergeCandidates.DataSource = Nothing
                Helper.DisplayException(oExp, Me, "Exception Displaying Changeset Details")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub ClearChangesetDetailsAndGrid()
            If (m_oBindingSourceChangesetDetails.DataSource IsNot Nothing) Then
                Dim oDtPrevious As DataTable = DirectCast(m_oBindingSourceChangesetDetails.DataSource, DataTable)
                oDtPrevious.Dispose()

                m_oBindingSourceChangesetDetails.DataSource = Nothing
            End If

            If (m_oBindingSourceWorkItems.DataSource IsNot Nothing) Then
                Dim oDtPrevious As DataTable = DirectCast(m_oBindingSourceWorkItems.DataSource, DataTable)
                oDtPrevious.Dispose()

                m_oBindingSourceWorkItems.DataSource = Nothing
            End If
        End Sub

        Private Sub cboBranchDestination_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboBranchDestination.SelectedIndexChanged
            Try
                ClearMergeCandidatesGrid()
                ClearChangesetDetailsAndGrid()
                GetMergeCandidates()
                btnMergeSelected.Enabled = cboBranchDestination.SelectedIndex >= 0
                grdMergeCandidates.Focus()
            Catch
            End Try
        End Sub

        Private Sub cboBranchDestination_EnabledChanged(sender As Object, e As EventArgs) Handles cboBranchDestination.EnabledChanged
            Try
                btnMergeSelected.Enabled = cboBranchDestination.Enabled
                btnCandidatesCheck.Enabled = cboBranchDestination.Enabled
                btnCandidatesUncheck.Enabled = cboBranchDestination.Enabled
            Catch
            End Try
        End Sub

        Private Sub btnMergeSelected_Click(sender As Object, e As EventArgs) Handles btnMergeSelected.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Merging selected changeset(s)...")

                If (m_oBindingSourceMergeCandidates.DataSource Is Nothing) Then Return

                Dim oDtCandidates As DataTable = DirectCast(m_oBindingSourceMergeCandidates.DataSource, DataTable)

                Dim aoDrSelectedRows As DataRow() = oDtCandidates.Select(Constants.MergeChangeset.BranchDataTableColumns.SELECTED & "= true")

                Dim oSourceBranch As TFSBranch = DirectCast(cboBranchSource.SelectedItem, TFSBranch)
                Dim oDesinationBranch As TFSBranch = DirectCast(cboBranchDestination.SelectedItem, TFSBranch)

                Dim szWorkingPath As String = My.Settings.WorkingDirectory
                If (String.IsNullOrWhiteSpace(szWorkingPath)) OrElse (Not Directory.Exists(szWorkingPath)) Then
                    Helper.DisplayMessage(Me, "You must go to the 'Settings' tab and specify a working directory before you can merge changesets.", "Unable to Merge Changeset(s)")
                    Return
                End If

                For Each oChangeSetRow As DataRow In aoDrSelectedRows
                    Dim iChangesetId As Integer = Convert.ToInt32(oChangeSetRow(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_ID))
                    SetStatus(String.Format("Merging changeset {0}...", iChangesetId))
                    TfsApi.MergeChangeset(Me.ParentForm, szWorkingPath, GetCollection(), oSourceBranch, oDesinationBranch, iChangesetId, Nothing)
                Next

                If (aoDrSelectedRows.Length > 0) Then
                    Helper.DisplayMessage(Me, String.Format("{0} changesets have been merged.", aoDrSelectedRows.Length), "Complete")
                End If

                ' Force a refresh of the data
                GetMergeCandidates()
            Catch oExp As Exception
                Cursor.Current = oCursor
                ClearChangesetDetailsAndGrid()
                ClearMergeCandidatesGrid()
                Helper.DisplayException(oExp, Me, "Exception Merging Changeset(s)")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub txtCandidateFilter_KeyUp(sender As Object, e As KeyEventArgs) Handles txtCandidateFilter.KeyUp
            Try
                If (e.KeyCode = Keys.Escape) Then
                    txtCandidateFilter.Text = String.Empty
                    m_oBindingSourceMergeCandidates.Filter = String.Empty
                    e.Handled = True
                    Return
                End If

                If (txtCandidateFilter.Text.Length < 3) Then
                    m_oBindingSourceMergeCandidates.Filter = String.Empty
                    Return
                End If

                Dim szFilter As String =
                        String.Format("[{1}] like '%{0}%' OR [{2}] like '%{0}%' OR Convert([{3}], 'System.String') like '%{0}%' OR Convert([{4}], 'System.String') like '%{0}%'",
                                      txtCandidateFilter.Text, Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_USER, Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_COMMENT,
                                      Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_ID, Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_DATE)
                m_oBindingSourceMergeCandidates.Filter = szFilter
            Catch
            End Try
        End Sub

        Private Sub ToggleCandidates(sender As Object, e As EventArgs) Handles btnCandidatesCheck.Click, btnCandidatesUncheck.Click
            Try
                Dim bSelected As Boolean = btnCandidatesCheck.Equals(sender)

                For iIndex As Integer = 0 To grdMergeCandidates.Rows.Count - 1
                    Dim oRow As DataGridViewRow = grdMergeCandidates.Rows(iIndex)
                    If (Not oRow.Visible) Then Continue For

                    Dim oDrCandidate As DataRow = DirectCast(oRow.DataBoundItem, DataRowView).Row()
                    oDrCandidate(Constants.MergeChangeset.BranchDataTableColumns.SELECTED) = bSelected
                Next
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Selecting/Unselecting Candidates")
            End Try
        End Sub

        Private Sub grdWorkItems_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles grdWorkItems.CellContentClick
            Try
                Dim oColumn As DataGridViewColumn = grdWorkItems.Columns()(e.ColumnIndex)
                If oColumn.GetType() <> GetType(DataGridViewLinkColumn) Then
                    Return
                End If

                Dim szUrl As String =
                        DirectCast(grdWorkItems.Rows()(e.RowIndex).DataBoundItem, DataRowView).Row()(Constants.MergeChangeset.ChangesetWorkItemDataTableColumns.WORK_ITEM_LINK).ToString()
                Process.Start(szUrl)
            Catch
            End Try
        End Sub

        Private Sub grdMergeCandidates_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles grdMergeCandidates.CellContentClick
            Try
                Dim oColumn As DataGridViewColumn = grdMergeCandidates.Columns()(e.ColumnIndex)
                If oColumn.GetType() <> GetType(DataGridViewLinkColumn) Then
                    Return
                End If

                Dim szUrl As String = DirectCast(grdMergeCandidates.Rows()(e.RowIndex).DataBoundItem, DataRowView).Row()(Constants.MergeChangeset.BranchDataTableColumns.CHANGESET_LINK).ToString()
                Process.Start(szUrl)
            Catch
            End Try
        End Sub

        Private Sub m_oBindingSourceMergeCandidates_ListChanged(sender As Object, e As ListChangedEventArgs) Handles m_oBindingSourceMergeCandidates.ListChanged
            Try
                Dim iCount As Integer = grdMergeCandidates.Rows.Count
                lblCandidatesShowing.Text = "Showing: "
                If (iCount > 0) Then lblCandidatesShowing.Text &= iCount
            Catch
            End Try
        End Sub
    End Class
End Namespace